//
//  ACCalendarManager.m
//  ACFramework
//
//  Created by caoyq on 2107/12/19.
//

#import "ACCalendarManager.h"
#import <EventKit/EventKit.h>
#import "UIAlertController+ACExt.h"

static NSCalendar *calendar = nil;

@implementation ACCalendarManager

+ (instancetype)gregorian
{
    static ACCalendarManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        //公历
        calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    });
    return instance;
}

#pragma mark - private

///当前日期组件
- (NSDateComponents *)currentDateComponents
{
    NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekOfMonth | NSCalendarUnitWeekdayOrdinal;
    NSDateComponents *dateComponent = [calendar components:unitFlags fromDate:[NSDate date]];
    return dateComponent;
}

#pragma mark - public methods

- (NSInteger)curYear
{
    return [self currentDateComponents].year;
}

- (NSInteger)curMonth
{
    return [self currentDateComponents].month;
}

- (NSInteger)curDay
{
    return [self currentDateComponents].day;
}

- (NSInteger)curHour
{
    return [self currentDateComponents].hour;
}

- (NSInteger)curMinute
{
    return [self currentDateComponents].minute;
}

- (NSInteger)curSecond
{
    return [self currentDateComponents].second;
}

- (NSInteger)curWeekday
{
    return [self currentDateComponents].weekday;
}

- (NSInteger)curWeekOfMonth
{
    return [self currentDateComponents].weekOfMonth;
}

- (NSInteger)curWeekOfYear
{
    return [self currentDateComponents].weekOfYear;
}

#pragma mark - 获取天数

- (NSInteger)numberOfDaysInCurrentMonth
{
    return [self numberOfDaysInDate:[NSDate date]];
}

- (NSInteger)numberOfDaysInDate: (NSDate *)date
{
    NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
    return range.length;
}

#pragma mark - 获取date

- (NSDate *)dateWithTimeStamp: (NSTimeInterval)timeStamp
{
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeStamp];
    return date;
}

- (NSDate *)dateOfFirstDayInCurrentMonth
{
    return [self dateOfFirstDayInDate:[NSDate date]];
}

- (NSDate *)dateOfLastDayInCurrentMonth
{
    return [self dateOfLastDayInDate:[NSDate date]];
}

- (NSDate *)dateOfFirstDayInDate: (NSDate *)date
{
    return [self dateAnyWithType:ACCalendarTypeDay baseDate:date value:1];
}

- (NSDate *)dateOfLastDayInDate: (NSDate *)date
{
    NSInteger dayCount = [self numberOfDaysInDate:date];
    return [self dateAnyWithType:ACCalendarTypeDay baseDate:date value:dayCount];
}

- (NSDate *)dateOfPreviousMonthInDate: (NSDate *)date
{
    return [self dateDifferenceWithType:ACCalendarTypeMonth baseDate:date difference:-1];
}

- (NSDate *)dateOfNextMonthInDate: (NSDate *)date
{
    return [self dateDifferenceWithType:ACCalendarTypeMonth baseDate:date difference:1];
}

#pragma mark - 获取星期几

- (NSInteger)indexOfWeekWithFirstDayInCurrentMonth
{
    NSDate *firstDate = [self dateOfFirstDayInCurrentMonth];
    return [self indexOfWeekWithDate:firstDate];
}

- (NSInteger)indexOfWeekWithDate: (NSDate *)date
{
    NSDateComponents *comps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitWeekday fromDate:date];
    // 直接调用自己weekDay属性
    NSInteger weekday = [comps weekday];
    //日历从周日计算起
    weekday--;
    if (weekday == 7) {
        return 0;
    }
    return weekday;
}

#pragma mark - 时间戳

+ (NSTimeInterval)timeStampFromDateString: (NSString *)dateString formatType: (ACCalendarFormatType)formatType
{
    NSString *format = [self formatFromType:formatType];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:format];
    NSDate *date = [formatter dateFromString:dateString];
    return [self timeStampFromDate:date];
}

+ (NSTimeInterval)timeStampFromDate: (NSDate *)date
{
    NSTimeInterval stamp = [date timeIntervalSince1970];
    return stamp;
}

#pragma mark - 日期时间 字符串

- (NSString *)stringWithDate: (NSDate *)date format: (NSString *)format
{
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:format];
    return [dateFormat stringFromDate:date];
}

- (NSString *)stringFromTimestamp: (NSTimeInterval)timeStamp format: (NSString *)format
{
    NSDate *date = [self dateWithTimeStamp:timeStamp];
    NSString *time = [self stringWithDate:date format:format];
    return time;
}

- (NSString *)timerStringFromTimestamp: (NSTimeInterval)timeStamp format: (NSString *)format
{
    NSDate *date = [self dateWithTimeStamp:timeStamp];
    //和上面方法区分开来，这里要设置时区，只有在计算倒计时才需要
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    //设置时区，避免多出8小时的时差
    [dateFormat setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    [dateFormat setDateFormat:format];
    NSString *time = [dateFormat stringFromDate:date];
    return time;
}

#pragma mark - private

+ (NSString *)formatFromType: (ACCalendarFormatType)type
{
    NSString *format = nil;
    switch (type) {
        case ACCalendarFormatTypeYMD:
            format = @"yyyy-MM-dd";
            break;
        case ACCalendarFormatTypeHMS:
            format = @"HH:mm:ss";
            break;
        case ACCalendarFormatTypeYMDHM:
            format = @"yyyy-MM-dd HH:mm";
            break;
        default:
            format = @"yyyy-MM-dd HH:mm:ss";
            break;
    }
    return format;
}

/**
 获取一个指定日期的时间.
 
 给定一个基础日期，选择需要指定的日期类型，再自定义具体的日期值，最后得到由基础日期改变一个日期类型得到的指定日期时间.
 
 例如：获取当月5号日期date. {type=ACCalendarTypeDay, baseDate=[NSDate date], value=5}
 
 @param type     ACCalendarType 需要指定的日期类型
 @param baseDate 基础日期
 @param value    具体的日期值属性
 @return 指定的日期时间 date
 */
- (NSDate *)dateAnyWithType: (ACCalendarType)type baseDate: (NSDate *)baseDate value: (NSInteger)value
{
    NSCalendarUnit dayInfoUnits  = NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    // NSDateComponents封装了日期的组件,年月日时分秒等
    NSDateComponents *components = [calendar components: dayInfoUnits fromDate:baseDate];
    switch (type) {
        case ACCalendarTypeYear:
            components.year = value;
            break;
        case ACCalendarTypeMonth:
            components.month = value;
            break;
        case ACCalendarTypeDay:
            components.day = value;
            break;
        case ACCalendarTypeHour:
            components.hour = value;
            break;
        case ACCalendarTypeMinute:
            components.minute = value;
            break;
        case ACCalendarTypeSecond:
            components.second = value;
            break;
        default:
            break;
    }
    NSDate *dateAny = [calendar dateFromComponents:components];
    return dateAny;
}

/**
 获取一个日期进行差值运算的时间.
 
 给定一个基础日期，选择日期差值的修改类型，再自定义差值，最后得到：由基础日期对修改类型进行差值运算 而得到的日期值.
 
 例如：获取上个月的今天. {type:ACCalendarTypeMonth; baseDate:[NSDate date]; difference:-1}  (月份减一即可得到)
 
 特殊：2018-1-1 上个月就是 2017-12-1; 2018-1-31 下个月就是 2018-2-28,对于下个月没有这一天则会往前找，直到有日期为止。举例说明主要是为了标明差值运算会自动考虑这些特殊情况.
 
 @param type     ACCalendarType日期差值的修改类型
 @param baseDate  给定的基础日期
 @param difference 日期差，在基础日期时间上增减。正数表示增加，负数表示减少
 @return  日期差处理后的日期时间 date
 */
- (NSDate *)dateDifferenceWithType: (ACCalendarType)type baseDate: (NSDate *)baseDate difference: (NSInteger)difference
{
    NSDateComponents *curComps = [[NSDateComponents alloc] init];
    switch (type) {
        case ACCalendarTypeYear:
            curComps.year = difference;
            break;
        case ACCalendarTypeMonth:
            curComps.month = difference;
            break;
        case ACCalendarTypeDay:
            curComps.day = difference;
            break;
        case ACCalendarTypeHour:
            curComps.hour = difference;
            break;
        case ACCalendarTypeMinute:
            curComps.minute = difference;
            break;
        case ACCalendarTypeSecond:
            curComps.second = difference;
            break;
        default:
            break;
    }
    NSDate *dateDifference = [calendar dateByAddingComponents:curComps toDate:baseDate options:0];
    return dateDifference;
}

#pragma mark - 比较时间

- (NSString *)compareFromDate: (NSString *)startingDate toDate: (NSString *)resultDate
{
    NSDateFormatter *dateFomatter = [[NSDateFormatter alloc] init];
    dateFomatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.0";
    NSDate *start = [dateFomatter dateFromString:startingDate];
    //获取开始结束Date作比较
    NSDate *end = [dateFomatter dateFromString:resultDate];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    // 需要对比的时间数据
    NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth
    | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    // 对比时间差
    NSDateComponents *components = [calendar components:unit fromDate:start toDate:end options:0];
    NSString *result = @"";
    if (components.year > 0) {
        result = [NSString stringWithFormat:@"%ld年", components.year];
    }
    if (components.month > 0) {
        result = [NSString stringWithFormat:@"%@%ld个月", result,components.month];
    }
    if (components.day > 0) {
        result = [NSString stringWithFormat:@"%@%ld天", result,components.day];
    }
    if (components.hour > 0) {
        result = [NSString stringWithFormat:@"%@%ld小时", result,components.hour];
    }
    if (components.minute > 0) {
        result = [NSString stringWithFormat:@"%@%ld分", result,components.minute];
    }
    if (components.second > 0) {
        result = [NSString stringWithFormat:@"%@%ld秒", result,components.second];
    }
    return result;
}

+ (NSInteger)compareFromDate: (NSString *)fromDate toDate: (NSString *)toDate  formatType: (ACCalendarFormatType)formatType
{
    NSString *format = [self formatFromType:formatType];
    NSDateFormatter *dateformater = [[NSDateFormatter alloc] init];
    [dateformater setDateFormat:format];
    NSDate *dateA = [dateformater dateFromString:fromDate];
    NSDate *dateB = [dateformater dateFromString:toDate];
    NSComparisonResult result = [dateA compare:dateB];
    if (result == NSOrderedAscending)
    { //升序，a < b
        return -1;
    }else if (result == NSOrderedDescending)
    { // 降序, a > b
        return 1;
    }
    // NSOrderedSame 相等
    return 0;
}

#pragma mark - 友好时间显示

+ (NSString *)friendlyDisplayPastTime: (NSString *)pastTime
{
    //Tue May 21 10:56:45 +0800 2013
    
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *pastDate = [formatter dateFromString:pastTime];
    NSTimeInterval past = [pastDate timeIntervalSince1970]*1;
    
    NSDate* curDate = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval now = [curDate timeIntervalSince1970]*1;
    NSString *timeString=@"";
    
    NSTimeInterval value = now - past;
    
    //秒
    if (value < 60) {
        timeString = [NSString stringWithFormat:@"%f", value];
        timeString = [timeString substringToIndex:timeString.length-7];
        timeString=[NSString stringWithFormat:@"%@秒前", timeString];
        return timeString;
    }
    
    //分钟
    if (value / 3600 < 1) {
        timeString = [NSString stringWithFormat:@"%f", value / 60];
        timeString = [timeString substringToIndex:timeString.length-7];
        timeString=[NSString stringWithFormat:@"%@分钟前", timeString];
        return timeString;
    }
    
    //小时
    if (value / 86400 < 1) {
        timeString = [NSString stringWithFormat:@"%f", value/3600];
        timeString = [timeString substringToIndex:timeString.length-7];
        timeString=[NSString stringWithFormat:@"%@小时前", timeString];
        return timeString;
    }
    
    //不在上述范围内就显示一个固定时间
    NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init];
    [dateformatter setDateFormat:@"YYYY-MM-dd"];
    timeString = [NSString stringWithFormat:@"%@",[dateformatter stringFromDate:pastDate]];
    return timeString;
}

#pragma mark - 写入事件到系统日历中

+ (void)writeEventToCalendarWithTitle: (NSString *)title location: (NSString *)location startDate: (NSDate *)startDate endDate: (NSDate *)endDate notes: (NSString *)notes completion: (void (^)(NSError *error))completion
{
    EKEventStore *eventStore = [[EKEventStore alloc] init];
    
    //这一步就会弹出授权框，不用单独去判断是否授权
    if ([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
        [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
            if (error) {
                
            }else if (!granted) {
                [UIAlertController ac_showAlertWithTitle:@"当前日历服务未授权" message:@"请先去授权\n 设置 > 隐私 > 日历" actionTitles:@[@"确定"] cancelTitle:nil style:UIAlertControllerStyleAlert completion:nil];
            }else {
                EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
                //标题
                event.title  = title;
                //位置
                event.location = location;
                //开始时间(必须传)
                event.startDate = startDate;
                //结束时间(必须传)
                event.endDate   = endDate;
                //提前5分钟提醒
                [event addAlarm:[EKAlarm alarmWithRelativeOffset: -60.0f * 5.0f]];
                //备注
                event.notes = notes;
                
                [event setCalendar:[eventStore defaultCalendarForNewEvents]];
                NSError *err;
                [eventStore saveEvent:event span:EKSpanThisEvent error:&err];
                
                if (completion) {
                    completion(err);
                }
                return;
            }
            
            if (completion) {
                completion(error);
            }
        }];
    }
}

@end
